This is the code used to visualise and manage the output of the Xsense dot IMU data. The source code can be found on my github
Load the data
Lets start by defining a function to correctly load measurements:
Note that IMU’s do not start and stop measureing at the exact same time; even after synchronization the amount of elements per IMU (the length of measurement) differs. In my implementation of temporal relaignment I assumed that the time in SampletimeFine was synchronized, and excluded first or last elements accordingly to ensure dataframes are of equal length. This eases calculation since R prefers to calculate over lists of equal length.
Code
# Clean workspace and load dependenciesrm(list =ls())library(tidyr)library(dplyr)library(plotly)library(ggplot2)library(knitr)library(lubridate)# Here i defined what test subject refers to what directorty#! should probably think about PID here later on. # format: name, hz, skipheadingpp_info <-data.frame (# file, hz, skiprowbart =c("../../Logs/old/20240429_163145_bart/", 60, 7),other =c("../../Logs/new/20240502_192335/", 60, 10))LoadXsenseData <-function(nameofpp) { dir <- nameofpp[1] hz <-as.numeric(nameofpp[2]) skiprow <-as.numeric(nameofpp[3])#dir <- bart#hz <- 60 files <-list.files(path = dir, full.names =TRUE) data <-list()# Read CSV files of each directoryfor (i inseq_along(files)) { data[[i]] <-read.csv(files[i], header =TRUE, skip = skiprow) }# Ensure all dataframes have the same number of rows min_rows <-min(sapply(data, nrow)) data <-lapply(data, function(df) { df <- df[1:min_rows, , drop =FALSE]return(df) })# Adjust timefor (i inseq_along(data)) { rows <-nrow(data[[i]]) data[[i]]$TimeS <- ((1/hz) * (1:rows)) }# Initialize toreturn data frame with time column toreturn <-data.frame(time = data[[1]]$TimeS)# Calculate absolute valuesfor (i in1:length(data)) {if ("FreeAcc_X"%in%names(data[[i]])) { col_name <-paste0("FreeAcc_abs", i) toreturn[[col_name]] <-sqrt(data[[i]]$FreeAcc_X^2+ data[[i]]$FreeAcc_Y^2+ data[[i]]$FreeAcc_Z^2) }if ("Acc_X"%in%names(data[[i]])) { col_name <-paste0("A_abs", i) toreturn[[col_name]] <-sqrt(data[[i]]$Acc_X^2+ data[[i]]$Acc_Y^2+ data[[i]]$Acc_Z^2) }if ("Gyr_X"%in%names(data[[i]])) { col_name <-paste0("Gyr_abs", i) toreturn[[col_name]] <-sqrt(data[[i]]$Gyr_X^2+ data[[i]]$Gyr_Y^2+ data[[i]]$Gyr_Z^2) } }# Order the attributes of the dataframe toreturn_sorted <- toreturn[, sort(names(toreturn))]return(toreturn_sorted)}
Visualization
lets also define some functions to visualize the data
Code
# Some functions to visualize the acceleration and the Gyrplot_a <-function(df) {if ("A_abs1"%in%names(df)) { plot <-plot_ly(df, x =~time, y =~A_abs1, name ="marker1", type ="scatter", mode ="lines") %>%add_trace(y =~A_abs2, name ="marker 2") %>%add_trace(y =~A_abs3, name ="marker 3") %>%add_trace(y =~A_abs4, name ="marker 4") %>%add_trace(y =~A_abs5, name ="marker 5") %>%layout(title ="Absolute accelerations",xaxis =list(title ="Time"),yaxis =list(title ="A_abs Values")) |> bslib::card(full_screen =TRUE) }if ("FreeAcc_abs1"%in%names(df)) { plot <-plot_ly(df, x =~time, y =~FreeAcc_abs1, name ="marker1", type ="scatter", mode ="lines") %>%add_trace(y =~FreeAcc_abs2, name ="marker 2") %>%add_trace(y =~FreeAcc_abs3, name ="marker 3") %>%add_trace(y =~FreeAcc_abs4, name ="marker 4") %>%add_trace(y =~FreeAcc_abs5, name ="marker 5") %>%layout(title ="Absolute accelerations",xaxis =list(title ="Time"),yaxis =list(title ="FreeAcc_abs Values")) |> bslib::card(full_screen =TRUE) }return(plot)}plot_gyr <-function(df) { plot <-plot_ly(df, x =~time, y =~Gyr_abs1, name ="marker1", type ="scatter", mode ="lines") %>%add_trace(y =~Gyr_abs2, name ="marker 2") %>%add_trace(y =~Gyr_abs3, name ="marker 3") %>%add_trace(y =~Gyr_abs4, name ="marker 4") %>%add_trace(y =~Gyr_abs5, name ="marker 5") %>%layout(title ="Absolute Gyr",xaxis =list(title ="Time"),yaxis =list(title ="Gyr Values"))return(plot)}#! Maybe include a plotting function that takes the dataframe and the attribute to plot, assuming 5 markers?
Initial test
Lets load some data and see how it looks:
note: to increase performance I stored the calculated values and read them. This is faster than calculating all absolute values each time the program runs
Code
# Storing the calculated data# meting1 <- LoadXsenseData(pp_info[1:3,1])# write.csv(meting1, file = "example1.csv", row.names = FALSE)# Loading the calulated datameting1 <-read.csv("example1.csv")# Plot the calculated dataplot_a(meting1)